# Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
# HYPRE Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

@PACKAGE_INIT@

include(CMakeFindDependencyMacro)
# Temporarily clear CMAKE_FIND_PACKAGE_NAME to avoid warning when FindPkgConfig
# calls find_package_handle_standard_args internally
set(_old_find_package_name_top "${CMAKE_FIND_PACKAGE_NAME}")
unset(CMAKE_FIND_PACKAGE_NAME)
include(FindPkgConfig)
if(DEFINED _old_find_package_name_top)
  set(CMAKE_FIND_PACKAGE_NAME "${_old_find_package_name_top}")
else()
  unset(CMAKE_FIND_PACKAGE_NAME)
endif()

function(find_hypre_dependency name)
  string(TOUPPER ${name} UPPER_NAME)
  if(HYPRE_ENABLE_${UPPER_NAME})
    # 1) Try CMake package config non-fatally
    find_package(${name} CONFIG QUIET HINTS ${HYPRE_DEPENDENCY_DIRS})
    if(${name}_FOUND)
      message(STATUS "Found ${UPPER_NAME} (CMake package).")
      return()
    endif()

    # 2) Fallback to pkg-config
    # Note: FindPkgConfig is already included at the top level
    set(_pc_name "${name}")
    if("${UPPER_NAME}" STREQUAL "DSUPERLU")
      set(_pc_name "superlu_dist")
    endif()
    if(DEFINED TPL_${UPPER_NAME}_PKGCONFIG_NAME)
      set(_pc_name "${TPL_${UPPER_NAME}_PKGCONFIG_NAME}")
    endif()

    if(PKG_CONFIG_FOUND)
      # Seed PKG_CONFIG_PATH from HYPRE_DEPENDENCY_DIRS
      set(_old_pc_path "$ENV{PKG_CONFIG_PATH}")
      set(_pc_hints)
      foreach(_d IN LISTS HYPRE_DEPENDENCY_DIRS)
        if(EXISTS "${_d}/pkgconfig")
          list(APPEND _pc_hints "${_d}/pkgconfig")
        endif()
        get_filename_component(_parent "${_d}" DIRECTORY)
        if(EXISTS "${_parent}/lib/pkgconfig")
          list(APPEND _pc_hints "${_parent}/lib/pkgconfig")
        endif()
        if(EXISTS "${_parent}/lib64/pkgconfig")
          list(APPEND _pc_hints "${_parent}/lib64/pkgconfig")
        endif()
        if(EXISTS "${_parent}/share/pkgconfig")
          list(APPEND _pc_hints "${_parent}/share/pkgconfig")
        endif()
      endforeach()
      list(REMOVE_DUPLICATES _pc_hints)
      if(_pc_hints)
        if(_old_pc_path)
          set(ENV{PKG_CONFIG_PATH} "${_pc_hints}:$ENV{PKG_CONFIG_PATH}")
        else()
          set(ENV{PKG_CONFIG_PATH} "${_pc_hints}")
        endif()
      endif()

      # Temporarily clear CMAKE_FIND_PACKAGE_NAME to avoid warning when pkg_check_modules
      # calls find_package_handle_standard_args internally
      set(_old_find_package_name "${CMAKE_FIND_PACKAGE_NAME}")
      unset(CMAKE_FIND_PACKAGE_NAME)
      pkg_check_modules(PC_${UPPER_NAME} QUIET ${_pc_name})
      if(DEFINED _old_find_package_name)
        set(CMAKE_FIND_PACKAGE_NAME "${_old_find_package_name}")
      else()
        unset(CMAKE_FIND_PACKAGE_NAME)
      endif()

      # Restore PKG_CONFIG_PATH
      set(ENV{PKG_CONFIG_PATH} "${_old_pc_path}")

      if(PC_${UPPER_NAME}_FOUND)
        message(STATUS "Found ${UPPER_NAME} via pkg-config: ${_pc_name}")
        # Ensure an imported target exists matching the link interface recorded at install time
        if(NOT TARGET PkgConfig::PC_${UPPER_NAME})
          add_library(PkgConfig::PC_${UPPER_NAME} INTERFACE IMPORTED)
          # Prefer link flags if provided; otherwise use libraries
          set(_pc_ll "${PC_${UPPER_NAME}_LDFLAGS}")
          if(NOT _pc_ll AND PC_${UPPER_NAME}_LINK_LIBRARIES)
            set(_pc_ll "${PC_${UPPER_NAME}_LINK_LIBRARIES}")
          endif()
          if(PC_${UPPER_NAME}_INCLUDE_DIRS)
            set_target_properties(PkgConfig::PC_${UPPER_NAME}
              PROPERTIES
                INTERFACE_INCLUDE_DIRECTORIES "${PC_${UPPER_NAME}_INCLUDE_DIRS}")
          endif()
          if(_pc_ll)
            # It is OK if these contain full paths or -l/-L flags
            set_target_properties(PkgConfig::PC_${UPPER_NAME}
              PROPERTIES
                INTERFACE_LINK_LIBRARIES "${_pc_ll}")
          endif()
        endif()
        return()
      endif()
    endif()

    message(FATAL_ERROR "${UPPER_NAME} not found (no CMake package or pkg-config entry).")
  endif()
endfunction()

set(HYPRE_DEPENDENCY_DIRS "@HYPRE_DEPENDENCY_DIRS@")
set(HYPRE_ENABLE_BIGINT @HYPRE_ENABLE_BIGINT@)
set(HYPRE_ENABLE_MIXEDINT @HYPRE_ENABLE_MIXEDINT@)
set(HYPRE_ENABLE_SINGLE @HYPRE_ENABLE_SINGLE@)
set(HYPRE_ENABLE_LONG_DOUBLE @HYPRE_ENABLE_LONG_DOUBLE@)
set(HYPRE_ENABLE_COMPLEX @HYPRE_ENABLE_COMPLEX@)
set(HYPRE_ENABLE_MIXED_PRECISION @HYPRE_ENABLE_MIXED_PRECISION@)
set(HYPRE_ENABLE_HYPRE_BLAS @HYPRE_ENABLE_HYPRE_BLAS@)
set(HYPRE_ENABLE_HYPRE_LAPACK @HYPRE_ENABLE_HYPRE_LAPACK@)
set(HYPRE_ENABLE_PERSISTENT_COMM @HYPRE_ENABLE_PERSISTENT_COMM@)
set(HYPRE_ENABLE_FEI @HYPRE_ENABLE_FEI@)
set(HYPRE_ENABLE_MPI @HYPRE_ENABLE_MPI@)
set(HYPRE_ENABLE_OPENMP @HYPRE_ENABLE_OPENMP@)
set(HYPRE_ENABLE_HOPSCOTCH @HYPRE_ENABLE_HOPSCOTCH@)
set(HYPRE_ENABLE_PRINT_ERRORS @HYPRE_ENABLE_PRINT_ERRORS@)
set(HYPRE_ENABLE_TIMING @HYPRE_ENABLE_TIMING@)
set(HYPRE_ENABLE_HOST_MEMORY @HYPRE_ENABLE_HOST_MEMORY@)
set(HYPRE_ENABLE_TEST_USING_HOST @HYPRE_ENABLE_TEST_USING_HOST@)
set(HYPRE_ENABLE_CUDA @HYPRE_ENABLE_CUDA@)
set(HYPRE_ENABLE_HIP @HYPRE_ENABLE_HIP@)
set(HYPRE_ENABLE_SYCL @HYPRE_ENABLE_SYCL@)
set(HYPRE_ENABLE_UNIFIED_MEMORY @HYPRE_ENABLE_UNIFIED_MEMORY@)
set(HYPRE_ENABLE_CUDA_STREAMS @HYPRE_ENABLE_CUDA_STREAMS@)
set(HYPRE_ENABLE_DEVICE_MALLOC_ASYNC @HYPRE_ENABLE_DEVICE_MALLOC_ASYNC@)
set(HYPRE_ENABLE_THRUST_NOSYNC @HYPRE_ENABLE_THRUST_NOSYNC@)
set(HYPRE_ENABLE_CUSPARSE @HYPRE_ENABLE_CUSPARSE@)
set(HYPRE_ENABLE_CUBLAS @HYPRE_ENABLE_CUBLAS@)
set(HYPRE_ENABLE_CURAND @HYPRE_ENABLE_CURAND@)
set(HYPRE_ENABLE_CUSOLVER @HYPRE_ENABLE_CUSOLVER@)
set(HYPRE_ENABLE_GPU_AWARE_MPI @HYPRE_ENABLE_GPU_AWARE_MPI@)
set(HYPRE_ENABLE_GPU_PROFILING @HYPRE_ENABLE_GPU_PROFILING@)
set(HYPRE_ENABLE_ROCSPARSE @HYPRE_ENABLE_ROCSPARSE@)
set(HYPRE_ENABLE_ROCBLAS @HYPRE_ENABLE_ROCBLAS@)
set(HYPRE_ENABLE_ROCRAND @HYPRE_ENABLE_ROCRAND@)
set(HYPRE_ENABLE_ROCSOLVER @HYPRE_ENABLE_ROCSOLVER@)
set(HYPRE_ENABLE_ONEMKLSPARSE @HYPRE_ENABLE_ONEMKLSPARSE@)
set(HYPRE_ENABLE_ONEMKLBLAS @HYPRE_ENABLE_ONEMKLBLAS@)
set(HYPRE_ENABLE_ONEMKLRAND @HYPRE_ENABLE_ONEMKLRAND@)
set(HYPRE_BUILD_EXAMPLES @HYPRE_BUILD_EXAMPLES@)
set(HYPRE_BUILD_TESTS @HYPRE_BUILD_TESTS@)
set(HYPRE_ENABLE_DSUPERLU @HYPRE_ENABLE_DSUPERLU@)
set(HYPRE_ENABLE_MAGMA @HYPRE_ENABLE_MAGMA@)
set(HYPRE_ENABLE_CALIPER @HYPRE_ENABLE_CALIPER@)
set(HYPRE_ENABLE_UMPIRE @HYPRE_ENABLE_UMPIRE@)
set(HYPRE_ENABLE_UMPIRE_HOST @HYPRE_ENABLE_UMPIRE_HOST@)
set(HYPRE_ENABLE_UMPIRE_DEVICE @HYPRE_ENABLE_UMPIRE_DEVICE@)
set(HYPRE_ENABLE_UMPIRE_UM @HYPRE_ENABLE_UMPIRE_UM@)
set(HYPRE_ENABLE_UMPIRE_PINNED @HYPRE_ENABLE_UMPIRE_PINNED@)
set(HYPRE_HAVE_MPI_COMM_F2C @HYPRE_HAVE_MPI_COMM_F2C@)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")

if (UNIX)
  list(APPEND TPL_LIBRARIES m)
endif()

if(NOT HYPRE_ENABLE_HYPRE_BLAS)
  find_dependency(BLAS)
endif()

if(NOT HYPRE_ENABLE_HYPRE_LAPACK)
  find_dependency(LAPACK)
endif()

# Synthesize BLAS::BLAS if module only provided BLAS_LIBRARIES
if(NOT HYPRE_ENABLE_HYPRE_BLAS)
  if(NOT TARGET BLAS::BLAS AND DEFINED BLAS_LIBRARIES AND BLAS_LIBRARIES)
    add_library(BLAS::BLAS INTERFACE IMPORTED)
    set_target_properties(BLAS::BLAS PROPERTIES
      INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}")
  endif()
endif()

# Synthesize LAPACK::LAPACK if module only provided LAPACK_LIBRARIES
if(NOT HYPRE_ENABLE_HYPRE_LAPACK)
  if(NOT TARGET LAPACK::LAPACK AND DEFINED LAPACK_LIBRARIES AND LAPACK_LIBRARIES)
    add_library(LAPACK::LAPACK INTERFACE IMPORTED)
    set_target_properties(LAPACK::LAPACK PROPERTIES
      INTERFACE_LINK_LIBRARIES "${LAPACK_LIBRARIES}")
  endif()
endif()

if(HYPRE_ENABLE_MPI)
  enable_language(C)
  find_dependency(MPI @MPI_C_VERSION@ COMPONENTS C)
endif()

if(HYPRE_ENABLE_OPENMP)
  find_dependency(OpenMP)
endif()

find_hypre_dependency(caliper)
find_hypre_dependency(dsuperlu)
find_hypre_dependency(magma)
find_hypre_dependency(umpire)

if(HYPRE_ENABLE_CUDA OR HYPRE_ENABLE_HIP OR HYPRE_ENABLE_SYCL)
  # List of required GPU libraries
  set(REQUIRED_GPU_COMPONENTS)

  if(HYPRE_ENABLE_CUDA)
    list(APPEND REQUIRED_GPU_COMPONENTS cudart)
    if(HYPRE_ENABLE_CUSPARSE)
      list(APPEND REQUIRED_GPU_COMPONENTS cusparse)
    endif()

    if(HYPRE_ENABLE_CUBLAS)
      list(APPEND REQUIRED_GPU_COMPONENTS cublas)
    endif()

    if(HYPRE_ENABLE_CURAND)
      list(APPEND REQUIRED_GPU_COMPONENTS curand)
    endif()

    if(HYPRE_ENABLE_CUSOLVER)
      list(APPEND REQUIRED_GPU_COMPONENTS cusolver)
    endif()
  elseif(HYPRE_ENABLE_HIP)
    if(HYPRE_ENABLE_ROCSPARSE)
      list(APPEND REQUIRED_GPU_COMPONENTS rocsparse)
    endif()

    if(HYPRE_ENABLE_ROCBLAS)
      list(APPEND REQUIRED_GPU_COMPONENTS rocblas)
    endif()

    if(HYPRE_ENABLE_ROCRAND)
      list(APPEND REQUIRED_GPU_COMPONENTS rocrand)
    endif()

    if(HYPRE_ENABLE_ROCSOLVER)
      list(APPEND REQUIRED_GPU_COMPONENTS rocsolver)
    endif()
  elseif(HYPRE_ENABLE_SYCL)
    if(HYPRE_ENABLE_ONEMKLSPARSE)
      list(APPEND REQUIRED_GPU_COMPONENTS onemklsparse)
    endif()

    if(HYPRE_ENABLE_ONEMKLBLAS)
      list(APPEND REQUIRED_GPU_COMPONENTS onemklblas)
    endif()

    if(HYPRE_ENABLE_ONEMKLRAND)
      list(APPEND REQUIRED_GPU_COMPONENTS onemklrand)
    endif()
  endif()

  if(REQUIRED_GPU_COMPONENTS)
    if(HYPRE_ENABLE_CUDA)
      set(GPU_TOOLKIT_NAME "CUDA")
      message(STATUS "Finding CUDA Toolkit components: ${REQUIRED_GPU_COMPONENTS}")
      find_dependency(CUDAToolkit REQUIRED COMPONENTS ${REQUIRED_GPU_COMPONENTS})
      set(GPU_TOOLKIT_FOUND ${CUDAToolkit_FOUND})
      set(GPU_TOOLKIT_VERSION ${CUDAToolkit_VERSION})

    elseif(HYPRE_ENABLE_HIP)
      # Add HIP root to prefix path to find ROCm components
      if(DEFINED ROCM_PATH)
        set(HIP_PATH ${ROCM_PATH})
      elseif(DEFINED ENV{ROCM_PATH})
        set(HIP_PATH $ENV{ROCM_PATH})
      elseif(DEFINED rocm_ROOT)
        set(HIP_PATH ${rocm_ROOT})
      elseif(DEFINED ENV{ROCM_ROOT})
        set(HIP_PATH $ENV{ROCM_ROOT})
      elseif(DEFINED hip_ROOT)
        set(HIP_PATH ${hip_ROOT})
      elseif(DEFINED ENV{hip_ROOT})
        set(HIP_PATH $ENV{hip_ROOT})
      elseif(EXISTS "/opt/rocm")
        set(HIP_PATH "/opt/rocm")
      else()
        message(WARNING "ROCM_PATH or HIP_PATH not set. Linking to ROCm libraries may not work.")
      endif()

      # Add HIP path to prefix path to find ROCm components
      list(APPEND CMAKE_PREFIX_PATH "${HIP_PATH}")

      set(GPU_TOOLKIT_NAME "HIP")
      message(STATUS "Finding HIP Toolkit components: ${REQUIRED_GPU_COMPONENTS}")
      find_dependency(hip REQUIRED)
      set(GPU_TOOLKIT_FOUND ${hip_FOUND})
      set(GPU_TOOLKIT_VERSION ${hip_VERSION})

      # Find ROCm components
      foreach(component ${REQUIRED_GPU_COMPONENTS})
        find_dependency(${component} REQUIRED)
      endforeach()

    elseif(HYPRE_ENABLE_SYCL)
      set(GPU_TOOLKIT_NAME "IntelSYCL")
      message(STATUS "Finding IntelSYCL Toolkit components: ${REQUIRED_GPU_COMPONENTS}")
      find_dependency(IntelSYCL REQUIRED)
      set(GPU_TOOLKIT_FOUND ${IntelSYCL_FOUND})
      set(GPU_TOOLKIT_VERSION ${IntelSYCL_VERSION})
    endif()

    if(GPU_TOOLKIT_FOUND)
      message(STATUS "GPU Toolkit found: ${GPU_TOOLKIT_NAME} ${GPU_TOOLKIT_VERSION}")
      set(MISSING_COMPONENTS)
      foreach(component ${REQUIRED_GPU_COMPONENTS})
        if(HYPRE_ENABLE_CUDA AND NOT TARGET CUDA::${component})
          list(APPEND MISSING_COMPONENTS ${component})
        elseif(HYPRE_ENABLE_HIP AND NOT TARGET roc::${component})
          list(APPEND MISSING_COMPONENTS ${component})
        elseif(HYPRE_ENABLE_SYCL AND NOT TARGET sycl::${component})
          list(APPEND MISSING_COMPONENTS ${component})
        endif()
      endforeach()
      if(MISSING_COMPONENTS)
        message(FATAL_ERROR "Required GPU components not found: ${MISSING_COMPONENTS}")
      else()
        message(STATUS "Required GPU components found: ${REQUIRED_GPU_COMPONENTS}")
      endif()
    else()
      message(FATAL_ERROR "GPU Toolkit not found.")
    endif()
  endif()
endif()

# Ensure BLAS::BLAS exists in consumer scope (some platforms/modules only set variables)
if(NOT TARGET BLAS::BLAS)
  # Try to find a proper imported target first
  find_package(BLAS QUIET)
  if(NOT TARGET BLAS::BLAS)
    add_library(BLAS::BLAS INTERFACE IMPORTED)
    if(DEFINED BLAS_LIBRARIES AND BLAS_LIBRARIES)
      # Use detected library list
      set_target_properties(BLAS::BLAS PROPERTIES
        INTERFACE_LINK_LIBRARIES "${BLAS_LIBRARIES}")
    else()
      # Last resort: assume a plain 'blas' link is available
      set_target_properties(BLAS::BLAS PROPERTIES
        INTERFACE_LINK_LIBRARIES "blas")
    endif()
  endif()
endif()

# Ensure LAPACK::LAPACK exists in consumer scope
if(NOT TARGET LAPACK::LAPACK)
  find_package(LAPACK QUIET)
  if(NOT TARGET LAPACK::LAPACK)
    add_library(LAPACK::LAPACK INTERFACE IMPORTED)
    if(DEFINED LAPACK_LIBRARIES AND LAPACK_LIBRARIES)
      set_target_properties(LAPACK::LAPACK PROPERTIES
        INTERFACE_LINK_LIBRARIES "${LAPACK_LIBRARIES}")
    else()
      set_target_properties(LAPACK::LAPACK PROPERTIES
        INTERFACE_LINK_LIBRARIES "lapack")
    endif()
  endif()
endif()

include("${CMAKE_CURRENT_LIST_DIR}/HYPRETargets.cmake")
